home *** CD-ROM | disk | FTP | other *** search
- /*
- * Plane.C - methods for plane manipulations.
- *
- * Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
- * University of Berne, Switzerland
- * Copyright (C) 1989, 1991, Craig E. Kolb
- * All rights reserved.
- *
- * This software may be freely copied, modified, and redistributed
- * provided that this copyright notice is preserved on all copies.
- *
- * You may not distribute this software, in whole or in part, as part of
- * any commercial product without the express consent of the authors.
- *
- * There is no warranty or other guarantee of fitness of this software
- * for any purpose. It is provided solely "as is".
- *
- */
-
- #include "Plane.h"
-
- //___________________________________________________________ Plane
-
- Plane::Plane(const Vector& position, const Vector& normal)
- : pos(position), n(normal)
- {
- if (n.normalize() == 0)
- n.normalize();
- D = pos^n;
- }
-
- GeoObject* Plane::create(const Vector& position, const Vector& normal)
- {
- if (equal(normal.sqr(), 0))
- return NULL;
-
- return new Plane(position, normal);
- }
-
- /*
- * intersect plane with ray.
- */
-
- int Plane::intersect(const Ray& ray, real minDist, real& maxDist)
- {
- intersectionTests++;
-
- real t = n^ray.getDir();
- if (fabs(t) < minDist)
- return FALSE;
-
- t = (D - (ray.getOrig()^n))/t;
-
- if (t > minDist && t < maxDist) {
- maxDist = t;
- intersections++;
- return TRUE;
- }
- return FALSE;
- }
-
- /*
- * Compute plane normal
- */
-
- Vector Plane::normal(const Vector&) const
- {
- return n;
- }
-
- /*
- * tesselate splits a plane into a polygon (I know it's impossible).
- * It is done by intersecting the plane with the bounding volume. The
- * resulting polygon is the visible part of the plane within the bounding
- * volume.
- */
-
- PolygonList* Plane::tesselate(const BoundingBox& bbox)
- {
- int i;
- BoundingBox tbbox(bbox);
-
- if (trans != NULL)
- tbbox = bbox.transform(*itrans);
-
- /*
- * compute the points on the bounding volume
- */
- Vector bottom[4];
- bottom[0] = Vector(tbbox.xmin(), tbbox.ymin(), tbbox.zmin());
- bottom[1] = Vector(tbbox.xmax(), tbbox.ymin(), tbbox.zmin());
- bottom[2] = Vector(tbbox.xmax(), tbbox.ymax(), tbbox.zmin());
- bottom[3] = Vector(tbbox.xmin(), tbbox.ymax(), tbbox.zmin());
-
- Vector top[4];
- top[0] = Vector(tbbox.xmin(), tbbox.ymin(), tbbox.zmax());
- top[1] = Vector(tbbox.xmax(), tbbox.ymin(), tbbox.zmax());
- top[2] = Vector(tbbox.xmax(), tbbox.ymax(), tbbox.zmax());
- top[3] = Vector(tbbox.xmin(), tbbox.ymax(), tbbox.zmax());
-
- Polygon* p = new Polygon(4);
- PolygonList* polys = NULL;
- Vector iPoint;
- int pointsOnPlane;
-
- for (i=0; i<4; i++) {
- if (pointsOnPlane=intersectPlaneWithSegment(bottom[i], top[i], iPoint)) {
- if (pointsOnPlane == 2) {
- p->addVertex(bottom[i]);
- p->addVertex(top[i]);
- }
- else
- p->addVertex(iPoint);
- }
- }
- for (i=0; i<4 && p->numVertices() < 4; i++) {
- if (pointsOnPlane=intersectPlaneWithSegment(top[i], top[(i+1)%4], iPoint)) {
- if (pointsOnPlane == 2) {
- p->addVertex(top[i]);
- p->addVertex(top[(i+1)%4]);
- }
- else
- p->addVertex(iPoint);
- }
- }
- for (i=0; i<4 && p->numVertices() < 4; i++) {
- if (pointsOnPlane=intersectPlaneWithSegment(bottom[i], bottom[(i+1)%4], iPoint)) {
- if (pointsOnPlane == 2) {
- p->addVertex(bottom[i]);
- p->addVertex(bottom[(i+1)%4]);
- }
- else
- p->addVertex(iPoint);
- }
- }
-
- if (p->numVertices() < 3) {
- delete p;
- p = NULL;
- }
- else if (p->numVertices() == 4) {
- Vector p1 = p->vertex(0), p2 = p->vertex(1),
- p3 = p->vertex(2), p4 = p->vertex(3);
-
- /*
- * check if any two edges intersects
- * -> if yes, swap the corresponding points
- */
- if (!equal(((p2-p1)*(p4-p3)).sqr(),0)) {
- Polygon* swapedP = new Polygon(p1, p2, p4, p3);
- delete p;
- p = swapedP;
- }
- else if (!equal(((p4-p1)*(p2-p3)).sqr(),0)) {
- Polygon* swapedP = new Polygon(p2, p1, p3, p4);
- delete p;
- p = swapedP;
- }
- }
-
- if (p != NULL) {
- if (trans != NULL)
- p->transform(*trans);
- polys = new PolygonList(1);
- polys->append(p);
- }
-
- return polys;
- }
-
-
- /*
- * Intersect segment p1,p2 with the plane. The return values are
- * 0 (no intersection), 1 (one intersection) or 2 (segment is on the plane).
- */
-
- int Plane::intersectPlaneWithSegment(const Vector& p1, const Vector& p2, Vector& h)
- {
- /*
- * calculate distance to plane for points p1, p2
- */
- real d1 = (p1 - pos)^n;
- real d2 = (p2 - pos)^n;
-
- /*
- * Test if one (both) endpoint(s) of the segment is one the plane.
- */
- if (equal(d1, 0)) {
- if (equal(d2,0))
- return 2;
- else {
- h = p1;
- return 1;
- }
- }
- else if (equal(d2, 0)) {
- h = p2;
- return 1;
- }
-
- /*
- * If the point p1 and p2 are on the same side of the plane,
- * no intersection is possible.
- */
- if ((d1 < 0 && d2 < 0) || (d1 > 0 && d2 > 0))
- return 0;
-
- Vector dir = p2-p1; dir.normalize();
- real t = n^dir;
-
- h = p1 + ((D-(p1^n))/t)*dir;
-
- return 1;
- }
-
-
-